package netmorph.model;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringBufferInputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * Netmorph config file class
 * 
 * TODO: 
 * 
 *  - FIXME: APD prefix handling
 * 
 * @author risto
 *
 */
public class ConfigFile extends LinkedHashMap<String, String> {

	File file;
	
	String apdTsemPrefix = "pyr1";
	String environmentPhysicsPrefix = "pia";
	String[] regions = { "A", "V" };
	
	public ConfigFile() {
		defaults();
	}
	
	public ConfigFile(File input) throws FileNotFoundException, IOException {
		file = input;
		loadFile();
	}

	public ConfigFile(String config) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(new StringBufferInputStream(config)));
		while (true) {
			String line = br.readLine();
			if (line == null) break;
			if (!line.contains("=")) continue;
			
			String[] p = line.trim().split("=");
			put(p[0], p[1]);
		}
		br.close();
		sync();
	}
	
	public void loadFile() throws FileNotFoundException, IOException
	{
		BufferedReader br = new BufferedReader(new FileReader(file));
		while (true) {
			String line = br.readLine();
			if (line == null) break;
			if (!line.contains("=")) continue;
			
			String[] p = line.replaceAll(";", "").trim().split("=");
			put(p[0], p[1]);
		}
		br.close();
		sync();
	}

	public void writeFile(File out) throws IOException {
		PrintWriter pw = new PrintWriter(new FileWriter(out));
		for (String k : keySet()) {
			pw.println(k + "=" + get(k) + ";");
		}
		pw.flush();
		pw.close();
	}

	public double getD(String key) {
		return Double.parseDouble((String)get(key));
	}

	private void sync()
	{
		if (containsKey("APD.tsem.prefix")) {
			apdTsemPrefix = get("APD.tsem.prefix");
		}
		if (containsKey("regions")) {
			regions = get("regions").split("[\\s,]");
		}
		if (containsKey("environment_physics")) {
			environmentPhysicsPrefix = get("environment_physics");
		}
	}
	public List<String> getAllDendriteKeys()
	{
		List<String> keys = new ArrayList<String>();
		for (String s : keySet()) { 
			if (s.startsWith("all_dendrites.")) keys.add(s);
		}
		return keys;
	}

	public List<String> getApicalKeys()
	{
		List<String> keys = new ArrayList<String>();
		for (String s : keySet()) { 
			if (s.startsWith("APD.")) keys.add(s);
			if (s.startsWith(apdTsemPrefix+".")) keys.add(s);
		}
		return keys;
	}

	public List<String> getAxonKeys()
	{
		List<String> keys = new ArrayList<String>();
		for (String s : keySet()) { 
			if (s.startsWith("all_axons.")) keys.add(s);
		}
		return keys;
	}

	public List<String> getEnvironmentKeys()
	{
		List<String> keys = new ArrayList<String>();
		for (String s : keySet()) { 
			if (s.startsWith("environment_physics")) keys.add(s);
			if (s.startsWith(environmentPhysicsPrefix + ".")) keys.add(s);
		}
		return keys;
	}

	public List<String> getOutputKeys()
	{
		List<String> keys = new ArrayList<String>();
		for (String s : keySet()) { 
			if (s.startsWith("outattr")) keys.add(s);
		}
		keys.add("warnings_on");
		keys.add("reports_on");
		keys.add("progress_on");
		return keys;
	}

	public List<String> getRegionKeys()
	{
		List<String> keys = new ArrayList<String>();
		for (String s : keySet()) {
			for (String reg : regions) {
				if (s.startsWith(reg + ".")) keys.add(s);
			}
		}
		return keys;
	}
	
	public List<String> getGeneralKeys()
	{
		List<String> keys = new ArrayList<String>();
		keys.add("days");
		keys.add("dt");
		keys.add("events_append_seconds");
		keys.add("neurons");
		keys.add("populationsizepyramidal");
		keys.add("randomseed");
		keys.add("shape");
		keys.add("regions");
//		keys.add("growthfunction", "vanPelt");
//		keys.add("Afibreswithturns", "true");
//		keys.add("Dfibreswithturns", "true");
		keys.add("F_competes_with");

		keys.add("pia_attraction_repulsion_hypothesis");
		keys.add("use_specified_basal_direction");
		keys.add("specified_basal_direction_relx");
		keys.add("specified_basal_direction_rely");
		keys.add("specified_basal_direction_relz");
		keys.add("apical_specified_overrides_centroid");
		keys.add("pyramidal.min_basal");
		keys.add("pyramidal.max_basal");
		keys.add("pyramidal.basal.minangle");
		keys.add("pyramidal.basal.maxangle");
		keys.add("pyramidal.basal.force_model");

		return keys;
	}
	
	private void defaults()
	{
		put("substitute","APD:all_apical_pyramidal_dendrites");

		// AllDendrites
		
		put("all_dendrites.branching_model","van_Pelt");
		put("all_dendrites.B_inf","1.92");
		put("all_dendrites.tau","400000");
		put("all_dendrites.E_competes_with","same_arbor");
		put("all_dendrites.E","0.09");
		put("all_dendrites.S","0.3");
		put("all_dendrites.TSBM","van_Pelt");

		put("all_dendrites.terminal_segment_elongation_model","nonnorm_BESTL");
		put("all_dendrites.tsem.PDF","delta");
		put("all_dendrites.tsem.PDF.value","0");
		
		put("all_dendrites.tsem.branch.PDF","normal");
		put("all_dendrites.tsem.branch.PDF.mean","0.4");
		put("all_dendrites.tsem.branch.PDF.std","8");
		
		put("all_dendrites.elongation_rate_initialization_model","nonnorm_BESTL_length_distribution");
		put("all_dendrites.eri.PDF","normal");
		put("all_dendrites.eri.PDF.mean","0.0000334");
		put("all_dendrites.eri.PDF.std", "0.0000366");

		put("all_dendrites.arbor_elongation_model","van_Pelt");
		put("all_dendrites.elongation_rate_initialization_model","nonnorm_BESTL_length_distribution");
		put("all_dendrites.growth_F","0");
		put("all_dendrites.growth_nu0","0.00011152");
		put("all_dendrites.F_competes_with","same_arbor");
/*
		put("all_dendrites.eri.PDF","normal");
		put("all_dendrites.eri.PDF.mean","0.0000914464");
		put("all_dendrites.eri.PDF.std","0.0000365786");
*/
		put("all_dendrites.branch_angle_model","Balanced_Forces");
		put("all_dendrites.bam.PDF","normal");
		put("all_dendrites.bam.PDF.mean","-0.08");
		put("all_dendrites.bam.PDF.std","0.05");

		
		put("all_dendrites.TSTM","linear_rate");
		put("all_dendrites.turn_separation","0.7");
		put("all_dendrites.turn_rate","2");

		put("all_dendrites.direction_model","segment_history_tension");
//		put("all_dendrites.dirhistory_selection","none");
		put("all_dendrites.veeranglemin","0.4");
		put("all_dendrites.veeranglemax","0.7");
		put("all_dendrites.history_power","1.2");

		put("all_dendrites.dm_label","dendritedm");
		put("all_dendrites.dendritedm.direction_model","segment_history_tension");
		put("all_dendrites.dendritedm.dm_weight","1");
//		put("all_dendrites.dm_weight","1");

		put("all_dendrites.aem.PDF","delta");
		put("all_dendrites.aem.PDF.value","0");

		// Apical
		
		put("APD.branching_model", "van_Pelt");
		put("APD.B_inf", "0.1");
		put("APD.tau","400000");
		put("APD.E","0");
		put("APD.E_competes_with","same_arbor");

		put("APD.direction_model", "segment_history_tension");
//		put("APD.dirhistory_selection", "none");
		put("APD.veeranglemin", "0.0");
		put("APD.veeranglemax", "0.1");
		put("APD.history_power", "1.0");
		
		put("APD.arbor_elongation_model","van_Pelt");
		put("APD.growth_F","0");
		put("APD.growth_nu0","0.0052");
		put("APD.F_competes_with","same_arbor");

		put("APD.aem.PDF","delta");
		put("APD.aem.PDF.value","0");
				
		put("APD.terminal_segment_elongation_model","pyrAD_BESTLNN");
		put("APD.tsem.trunklength.PDF","normal");
		put("APD.tsem.trunklength.PDF.mean","570");
		put("APD.tsem.trunklength.PDF.std", "10");
		
		put("APD.tsem.obliques.PDF","normal");
		put("APD.tsem.obliques.PDF.mean", "0");
		put("APD.tsem.obliques.PDF.std", "0");
		put("APD.tsem.obliqueangle.PDF", "normal");
		put("APD.tsem.obliqueangle.PDF.mean", "0");
		put("APD.tsem.obliqueangle.PDF.std", "1");

		put("APD.tsem.branch.PDF", "normal");
		put("APD.tsem.branch.PDF.mean", "6");
		put("APD.tsem.branch.PDF.std", "1");

		put("APD.tsem.PDF","delta");
		put("APD.tsem.PDF.value", "0");
		
		put("APD.elongation_rate_initialization_model", "nonnorm_BESTL_length_distribution");
		put("APD.eri.PDF","normal");
		put("APD.eri.PDF.mean", "0.001021");
		put("APD.eri.PDF.std", "0.0000256");

		// TUFT
		put("APD.tsem.prefix","pyr1");
		put("pyr1.tuft.terminal_segment_elongation_model", "nonnorm_BESTL");
		
		put("pyr1.tuft.tsem.branch.PDF", "normal");
		put("pyr1.tuft.tsem.branch.PDF.mean", "0.8");
		put("pyr1.tuft.tsem.branch.PDF.std", "17");
		
		put("pyr1.tuft.tsem.PDF", "delta");
		put("pyr1.tuft.tsem.PDF.value", "0");
		
		put("pyr1.tuft.elongation_rate_initialization_model", "nonnorm_BESTL_length_distribution");
		put("pyr1.tuft.eri.PDF", "normal");
		put("pyr1.tuft.eri.PDF.mean", "0.0000700");
		put("pyr1.tuft.eri.PDF.std",  "0.0000409");

		put("pyr1.tuft.TSBM", "van_Pelt_specBM");
		put("pyr1.tuft.S", "0");
		put("pyr1.tuft.branching_model", "van_Pelt");
		put("pyr1.tuft.B_inf", "4.47");
		put("pyr1.tuft.tau", "400000");
		put("pyr1.tuft.E", "0.22");		
		put("pyr1.tuft.F_competes_with", "same_arbor");

		put("pyr1.tuft.branch_angle_model", "Balanced_Forces");		
		put("pyr1.tuft.bam.PDF", "normal");		
		put("pyr1.tuft.bam.PDF.mean", "-0.30");
		put("pyr1.tuft.bam.PDF.std", "0.01");		

		put("pyr1.tuft.direction_model", "segment_history_tension");		
//		put("pyr1.tuft.dirhistory_selection", "none");		

		put("pyr1.tuft.veeranglemin", "0.4");
		put("pyr1.tuft.veeranglemax", "0.7");
		put("pyr1.tuft.history_power", "1.2");		

		
		// OBLIQUES
		put("pyr1.oblique.terminal_segment_elongation_model", "nonnorm_BESTL");
		put("pyr1.oblique.tsem.branch.PDF", "normal");
		put("pyr1.oblique.tsem.branch.PDF.mean", "0.4");
		put("pyr1.oblique.tsem.branch.PDF.std", "8");
		put("pyr1.oblique.tsem.PDF", "delta");
		put("pyr1.oblique.tsem.PDF.value", "0");
		put("pyr1.oblique.elongation_rate_initialization_model", "nonnorm_BESTL_length_distribution");
		put("pyr1.oblique.eri.PDF", "normal");
		put("pyr1.oblique.eri.PDF.mean", "0.0000413");
		put("pyr1.oblique.eri.PDF.std",  "0.0000459");
		
		put("pyr1.oblique.TSBM", "van_Pelt_specBM");
		put("pyr1.oblique.S", "0");
		put("pyr1.oblique.branching_model", "van_Pelt");
		put("pyr1.oblique.B_inf", "1.11");
		put("pyr1.oblique.tau", "400000");
		put("pyr1.oblique.E", "0.01");		
		put("pyr1.oblique.E_competes_with", "same_arbor");		
		
		// Axon
		put("all_axons.eri.PDF", "normal");
		put("all_axons.eri.PDF.mean", "0");
		put("all_axons.eri.PDF.std", "0");
		put("all_axons.B_inf", "0");

/*
		put("all_axons.arbor_elongation_model", "van_Pelt"); 
		put("all_axons.elongation_rate_initialization_model", "nonnorm_BESTL_length_distribution"); 
		put("all_axons.growth_F", "0");
		put("all_axons.growth_nu0", "0.0005"); 
		put("all_axons.F_competes_with", "same_arbor"); 
		put("all_axons.eri.PDF", "normal"); 
		put("all_axons.eri.PDF.mean", "0.0005146"); 
		put("all_axons.eri.PDF.std", "0.0003978"); 
		put("all_axons.tau", "400000");

		put("all_axons.aem.PDF", "delta"); 
		put("all_axons.aem.PDF.value", "0"); 

		// lengte direct na branching event toegewezen 
		put("all_axons.terminal_segment_elongation_model", "nonnorm_BESTL"); 
		//put("all_axons.tsem.branch.PDF", "delta"); 
		put("all_axons.tsem.branch.PDF", "normal"); 
		put("all_axons.tsem.branch.PDF.mean", "6"); 
		put("all_axons.tsem.branch.PDF.std", "5"); 
		//put("all_axons.tsem.branch.PDF.value", "6"); 

		// should be 0 so as not to use tsem but depend on eri 
		put("all_axons.tsem.PDF", "delta"); 
		put("all_axons.tsem.PDF.value", "0"); 

		put("all_axons.branching_model", "van_Pelt"); 
		put("all_axons.B_inf", "0.1"); 
		put("all_axons.E_competes_with", "same_arbor"); 
		put("all_axons.E", "0.65"); 
		put("all_axons.TSBM", "van_Pelt"); 
		put("all_axons.S", "-0.44"); 
		
		put("all_axons.direction_model","segment_history_tension");
		put("all_axons.dm_label","axondm");
		put("all_axons.axondm.dm_weight","0.05");
		put("all_axons.axondm.direction_model","cell_attraction");
		
		put("all_axons.veeranglemin","0.25");
		put("all_axons.veeranglemax","1.0");
		put("all_axons.history_power","0.4");
*/
		// Environment
		
		put("environment_physics", "pia");
		put("pia.physical_boundary", "spherical");
//		put("pia.spherical_center", "(0,-10000,0)");
		put("pia.spherical_centerX", "0");
		put("pia.spherical_centerY", "-10000");
		put("pia.spherical_centerZ", "0");
		put("pia.spherical_radius", "10000");
		put("pia.spherical_maxrange", "140");
		put("pia.spherical_c_repulse", "0.05");
		
		// General
		
		put("days", "21");
		put("dt", "100");
		put("events_append_seconds", "0");
		put("neurons", "40");
		put("populationsizepyramidal", "0");
		put("randomseed", "0");
		put("shape", "regions");
		put("regions", "V");
//		put("growthfunction", "vanPelt");
//		put("Afibreswithturns", "true");
//		put("Dfibreswithturns", "true");
		put("F_competes_with", "same_arbor");

		put("pia_attraction_repulsion_hypothesis", "true");
		put("use_specified_basal_direction", "true");
		put("specified_basal_direction_relx", "0");
		put("specified_basal_direction_rely", "-1");
		put("specified_basal_direction_relz", "0");
		put("apical_specified_overrides_centroid", "true");
		put("pyramidal.min_basal", "7");
		put("pyramidal.max_basal", "7");
		put("pyramidal.basal.minangle", "0");
		put("pyramidal.basal.maxangle", "1.5");
		put("pyramidal.basal.force_model", "surface_division");

		// Regions
		put("V.neurons", "0");
		put("V.pyramidal", "1");
		put("V.minneuronseparation", "50");
		put("V.shape", "box");
		put("V.shape.width", "2000");
		put("V.shape.height", "100");
		put("V.shape.depth", "2000");
		put("V.centerX", "0");
		put("V.centerY", "-700");
		put("V.centerZ", "0");
		
		// Output
		
		put("outattr_make_full_Txt", "true");
		put("outattr_Txt_separate_files", "true");
		put("outattr_track_nodegenesis", "true");
		put("warnings_on", "stdout");
		put("reports_on", "file");
		put("progress_on", "file");
	}
}
